package pers.ree.demo.concurrent.interview;

import org.junit.Test;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 交替输出数字和字母,如A1B2C3
 */
public class AlternateOutput {

    private char[] alphabetArr = "ABCDEFG".toCharArray();
    private char[] numArr = "1234567".toCharArray();

    private Thread t1, t2;

    @Test
    public void useLockSupport() {
        t1 = new Thread(() -> {
            for (char c: numArr) {
                System.out.println(c);

                LockSupport.unpark(t2);

                LockSupport.park();
            }
        }, "t1");

        t2 = new Thread(() -> {
            for (char c: alphabetArr) {
                LockSupport.park();

                System.out.println(c);

                LockSupport.unpark(t1);
            }
        }, "t2");

        t1.start();
        t2.start();
    }


    private static CountDownLatch countDownLatch = new CountDownLatch(1);

    @Test
    public void useNotifyAndWait() {
        final Object o = new Object();

        new Thread(() -> {
            synchronized (o) {
                for (char c: numArr) {
                    System.out.println(c);

                    if (countDownLatch.getCount() > 0) {
                        System.out.println("countDownLatch count=" + countDownLatch.getCount());
                        countDownLatch.countDown();
                    }

                    try {
                        o.notify();
                        o.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                o.notify();
            }
        }, "t1").start();

        new Thread(() -> {
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            synchronized (o) {
                for (char c : alphabetArr) {
                    System.out.println(c);

                    try {
                        o.notify();
                        o.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                o.notify();
            }
        }, "t2").start();
    }

    @Test
    public void useCondition() {
        Lock lock = new ReentrantLock();

        Condition condition1 = lock.newCondition();
        Condition condition2 = lock.newCondition();

        new Thread(() -> {

            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            lock.lock();

            try {
                for (char c : numArr) {
                    System.out.println(c);

                    condition2.signal();
                    condition1.await();
                }

                condition2.signal();

            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }, "t1").start();

        new Thread(() -> {
            lock.lock();

            try {
                for (char c : alphabetArr) {
                    System.out.println(c);

                    if (countDownLatch.getCount() > 0) {
                        System.out.println("countDownLatch count=" + countDownLatch.getCount());
                        countDownLatch.countDown();
                    }

                    condition1.signal();
                    condition2.await();
                }

                condition1.signal();

            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }

        }, "t2").start();
    }
}
